              <div align="right">
${TARGET="offline"}                <a href="${LDAP_SDK_HOME_URL}" style="font-size: 85%">LDAP SDK Home Page</a>
${TARGET="offline"}                <br>
                <a href="${BASE}index.${EXTENSION}" style="font-size: 85%">Product Information</a>
              </div>

              <h2>Using Additional UnboundID-Specific Extended Operations</h2>

              <p>
                In addition to the standard extended operations described on the
                <a HREF="../getting-started/extended-operations.${EXTENSION}">Using Standard
                Extended Operations</a> page of the Getting Started Guide, the UnboundID LDAP SDK
                for Java also provides support for an additional set of extended operations that
                allow for enhanced functionality when interacting with the Ping Identity,
                UnboundID, and Nokia/Alcatel-Lucent 8661 Directory Server.  These extended
                operations will likely not work with any other directory, but can help provide an
                enhanced experience when using the Ping Identity, UnboundID, and
                Nokia/Alcatel-Lucent 8661 Directory Server.
              </p>

              <p></p>
              <h3>Clear Missed Notification Changes</h3>

              <p>
                The clear missed notification changes operation may be used to clear a server
                alarm condition about missed change notifications.
              </p>

              <p></p>
              <h3>Delete Notification Destination</h3>

              <p>
                The delete notification destination operation may be used to remove a notification
                destination, and all of its associated subscriptions, from the server.
              </p>

              <p></p>
              <h3>Delete Notification Subscription</h3>

              <p>
                The delete notification subscription operation may be used to remove a
                notification subscription from the server.
              </p>

              <p></p>
              <h3>Deliver and Consume Single-Use Token</h3>

              <p>
                The deliver single-use token operation may be used to generate a time-limited,
                single-use token and deliver it to a user through some out-of-band mechanism
                (e.g., email, SMS, voice call, etc.).  The consume single-use token operation maye
                be used to indicate that the user has received that token.  These operations may
                be useful for things like verifying that a user can receive email at a given
                address or SMS messages at a given mobile number.
              </p>

              <p></p>
              <h3>Deliver One-Time Password</h3>

              <p>
                The deliver one-time password operation may be used to generate a time-limited,
                single-use password and deliver it to a user through some out-of-band mechanism
                (e.g., email, SMS, voice call, etc.) after verifying that a provided static
                password is valid for that user.  This one-time password can be used to bind to
                the server via the UNBOUNDID-DELIVERED-OTP SASL mechanism as a means of performing
                two-factor authentication.
              </p>

              <p></p>
              <h3>Deliver Password Reset Token</h3>

              <p>
                The deliver password reset token operation may be used to generate a time-limited,
                single-use token and deliver it to a user through some out-of-band mechanism
                (e.g., email, SMS, voice call, etc.).  This token can be provided to the password
                modify operation in lieu of the user's current password in order to give that user
                the ability to choose a new password.  This can be used to help automate the
                process of resetting a password that the end user had forgotten or allowed to
                expire.
              </p>

              <p></p>
              <h3>Get Backup Compatibility Descriptor and Identify Backup Compatibility Problems</h3>

              <p>
                The get backup compatibility descriptor operation may be used to obtain a set of
                properties that a backend will use when creating a backup.  The backup compatibility
                descriptor will automatically be embedded in any backup performed by the server,
                but this operation may be used to get that descriptor without actually performing
                a backup.  The identify backup compatibility problems operation may be used to
                determine whether a backup with a given backup compatibility descriptor may be
                restored to that backend.  This set of operations is particularly useful when
                attempting to restore a backup from one server into another server, or when
                performing online replica initialization between instances, to ensure that the
                target instance will be able to properly handle the data contained in the backup.
              </p>

              <p></p>
              <h3>Get Changelog Batch</h3>

              <p>
                The get changelog batch operation may be used to retrieve information about a set
                of changes processed by the server.  This operation can be used via polling or by
                blocking for changes to become available, can be used to retrieve only a subset of
                changes matching a given set of criteria (e.g., only certain change types, only
                changes to certain attributes, etc.), and can safely be used across all replicas
                in the environment, even if their changelogs may contain a slightly different
                operation order as a result of the difference between changes being processed
                locally versus those received from replication.
              </p>

              <p></p>
              <h3>Get and List Configurations</h3>

              <p>
                The get configuration operation may be used to retrieve information about the
                server configuration.  This may be the current configuration, a known baseline
                configuration, or a configuration that the server may have held in the past.  The
                list configurations operation may be used to retrieve information about the set
                of configurations that can be retrieved using the get configuration operation.
                These operations may be used to help identify configuration differences between
                server instances, as well as to determine what configuration changes have been
                applied to a server over time.
              </p>

              <p></p>
              <h3>Get Connection ID</h3>

              <p>
                The get connection ID extended operation provides a mechanism that allows the
                client to request the connection ID that the Ping Identity, UnboundID, or
                Nokia/Alcatel-Lucent 8861 Directory Server has assigned to that client connection.
                This can be helpful because it allows the client to include that in logging or
                debugging information that makes it easier to correlate requests from the client
                with operations in the server's access log.
              </p>

              <p>
                The following code demonstrates the use of the get connection ID extended
                operation:
              </p>

              <pre>
GetConnectionIDExtendedResult result =
     (GetConnectionIDExtendedResult) connection.processExtendedOperation(
          new GetConnectionIDExtendedRequest());

// NOTE:  The processExtendedOperation method will only throw an exception
// if a problem occurs while trying to send the request or read the
// response.  It will not throw an exception because of a non-success
// response.

if (result.getResultCode() == ResultCode.SUCCESS)
{
  System.out.println("The directory server's connection ID for this " +
                     "connection is " + result.getConnectionID());
}
</pre>

              <p></p>
              <h3>Get Password Quality Requirements</h3>

              <p>
                The get password quality requirements may be used to retrieve information about
                the constraints that will be enforced for passwords for a given user in a
                specified operation.  This may be used to allow an application to provide
                guidelines when allowing a user to change his or her password, and may also
                provide information that an application may be able to leverage in order to
                perform some client-side validation for a proposed password.
              </p>

              <p></p>
              <h3>Get and Set Subtree Accessibility</h3>

              <p>
                The set subtree accessibility operation may be used to alter the accessibility of
                one or more subtrees in the DIT.  This operation can be used to make subtrees
                fully accessible, read-only, or hidden.  The get subtree accessibility operation
                can be used to retrieve information about subtree accessibility restrictions that
                are currently in place in the server.
              </p>

              <p></p>
              <h3>Get Supported OTP Delivery Mechanisms</h3>

              <p>
                The get supported OTP delivery mechanisms operation may be used to obtain
                information about the set of mechanisms that the server offers for conveying
                one-time passwords, password reset tokens, and single-use tokens to end users,
                and which of those mechanisms may be available for use by a specified user.
              </p>

              <p></p>
              <h3>List Notification Subscriptions</h3>

              <p>
                The list notification subscriptions operation may be used to obtain information
                about the set of notification destinations that have been defined, along with
                their associated subscriptions.
              </p>

              <p></p>
              <h3>Multi-Update</h3>

              <p>
                The multi-update operation provides a mechanism for sending information about
                multiple add, delete, modify, modify DN, and/or password modify operations that
                should be processed in a single request.  The client can indicate whether all of
                the changes should be processed as a single atomic unit, or whether they should be
                processed as if they had been separate requests.
              </p>

              <p></p>
              <h3>Password Policy State</h3>

              <p>
                The password policy state extended operation provides a powerful mechanism that can
                be used to retrieve and alter a number of properties related to a user's current
                password policy state.  The properties that are available are defined in the
                <tt>PasswordPolicyStateOperation</tt> object and include:
              </p>

              <ul>
                <li>
                  Retrieving the DN of the password policy configuration entry that governs the
                  associated user.
                  <br><br>
                </li>

                <li>
                  Getting, setting, and clearing the flag that indicates whether the user's account
                  is disabled.
                  <br><br>
                </li>

                <li>
                  Getting, setting, and clearing the time that the user's account expires and can
                  no longer be used.
                  <br><br>
                </li>

                <li>
                  Getting the length of time until the user's account expires.
                  <br><br>
                </li>

                <li>
                  Getting the time that the user's password was last changed.
                  <br><br>
                </li>

                <li>
                  Getting and clearing the time that the user was first warned about an upcoming
                  password expiration.
                  <br><br>
                </li>

                <li>
                  Getting the length of time until the user's password expires.
                  <br><br>
                </li>

                <li>
                  Getting the length of time until the user is eligible to be warned about an
                  upcoming password expiration.
                  <br><br>
                </li>

                <li>
                  Getting, setting, and clearing the set of times that a client has unsuccessfully
                  tried to authenticate as the user since the last successful login.
                  <br><br>
                </li>

                <li>
                  Getting the length of time until the user's account is unlocked after having been
                  locked due to too many failed attempts.
                  <br><br>
                </li>

                <li>
                  Getting the number of remaining failed attempts until the user's account is
                  locked.
                  <br><br>
                </li>

                <li>
                  Getting, setting, and clearing the time that the user last authenticated to the
                  server.
                  <br><br>
                </li>

                <li>
                  Getting the length of time that the user's account may remain idle before it is
                  locked for lack of use.
                  <br><br>
                </li>

                <li>
                  Getting, setting, and clearing the flag that indicates whether the user must
                  change his/her password before being allowed to perform any other operation.
                  <br><br>
                </li>

                <li>
                  Getting the length of time until the user account is locked because they have not
                  changed their password after an administrative reset.
                  <br><br>
                </li>

                <li>
                  Getting, setting, and clearing the times that the user account has authenticated
                  with grace logins after the password has expired.
                  <br><br>
                </li>

                <li>
                  Getting the number of available grace logins remaining.
                  <br><br>
                </li>

                <li>
                  Getting, setting, and clearing the time of the last forced password change with
                  which the user complied.
                  <br><br>
                </li>

                <li>
                  Getting the length of time until an upcoming forced password change time arrives.
                  <br><br>
                </li>

                <li>
                  Getting and clearing the password history values for the user account.
                  <br><br>
                </li>
              </ul>

              <p>
                Most of these operations depend on the server's password policy configuration, and
                many of them may not apply in all configurations.  For example, if password
                expiration is not enabled, then password policy state operations associated with
                password expiration may not be meaningful.  Nevertheless, this can be a powerful
                capability for administrators, particularly given that the server may not allow
                many of these values to be altered in any other way.
              </p>

              <p>
                The password policy state request needs to include the DN of the target user and a
                set of zero or more password policy state operations to process for that user.  If
                no password policy state operations are included in the request, then it will be
                interpreted as a "get all" request, in which the server will return the values of
                all password policy state properties listed above but will not alter anything.  If
                a specified set of password policy state operations is provided, then the server
                will only process those.  For any password policy state changes that are made, the
                server will also return the updated values for the associated properties in the
                response.
              </p>

              <p>
                The following example demonstrates the use of the password policy state operation
                in order to administratively disable a user's account:
              </p>

              <pre>
PasswordPolicyStateOperation disableOp =
     PasswordPolicyStateOperation.createSetAccountDisabledStateOperation(
          true);
PasswordPolicyStateExtendedRequest pwpStateRequest =
     new PasswordPolicyStateExtendedRequest(
              "uid=john.doe,ou=People,dc=example,dc=com", disableOp);
PasswordPolicyStateExtendedResult pwpStateResult =
     (PasswordPolicyStateExtendedResult)
     connection.processExtendedOperation(pwpStateRequest);

// NOTE:  The processExtendedOperation method will only throw an exception
// if a problem occurs while trying to send the request or read the
// response.  It will not throw an exception because of a non-success
// response.

if (pwpStateResult.getResultCode() == ResultCode.SUCCESS)
{
  boolean isDisabled = pwpStateResult.getBooleanValue(
       PasswordPolicyStateOperation.OP_TYPE_GET_ACCOUNT_DISABLED_STATE);
  if (isDisabled)
  {
    System.out.println("The user account has been disabled.");
  }
  else
  {
    System.out.println("The user account is not disabled.");
  }
}
</pre>

              <p></p>
              <h3>Set Notification Destination</h3>

              <p>
                The set notification destination operation may be used to create or update a
                notification destination in the server.
              </p>

              <p></p>
              <h3>Set Notification Subscription</h3>

              <p>
                The set notification destination operation may be used to create or update a
                notification subscription in the server.
              </p>

              <p></p>
              <h3>Start and End Administrative Session</h3>

              <p>
                The start administrative session operation may be used to indicate that the client
                is about to perform a sequence of operations that are intended for administrative
                use.  It may optionally request that subsequent operations in that session be
                processed in a separate, dedicated pool of worker threads that are not used for
                processing normal operations and may be used to help an administrator diagnose a
                problem or take corrective action even if all normal worker threads are currently
                busy processing expensive operations.  The end administrative session operation
                may be used to indicate that any following requests should not be considered part
                of the administrative session.
              </p>

              <p></p>
              <h3>Start and End Batched Transaction</h3>

              <p>
                The start batched transaction and end batched transaction extended operations, and
                the associated batched transaction specification request control, are based on the
                specification in draft-zeilenga-ldap-txn.  They can be used to create a batched
                transaction in which multiple write operations are performed as a single atomic
                unit.  First, a start batched transaction request is sent to the server, which will
                return a start batched transaction result containing a transaction ID.  Each
                operation that should be performed as part of that transaction should then include
                the batched transaction specification control containing that transaction ID.
                Finally, the end batched transaction request may be sent to the server to either
                commit or abort the transaction.  If any of the operations performed as part of the
                transaction included response controls, then they will also be made available in
                the end transaction result.
              </p>

              <p>
                Note that transactions processed in this manner can only contain add, delete,
                modify, and modify DN operations, as well as the password modify extended
                operation.  It is not possible to include abandon, bind, compare, search, unbind,
                or other types of extended operations as part of transaction.  However, it is
                possible to use the LDAP assertions control to ensure that an entry being updated
                matches an expected set of criteria, and it is also possible to use the LDAP
                pre-read and/or post-read control to retrieve copies of the entry immediately
                before and/or after a given write was performed.
              </p>

              <p>
                The following example illustrates the use of the start and end batched transaction
                operations and the batched transaction specification request control to modify two
                entries as a single atomic update:
              </p>

              <pre>
// Send the start transaction operation and get the transaction ID.
StartBatchedTransactionExtendedRequest startTxnRequest =
     new StartBatchedTransactionExtendedRequest();
StartBatchedTransactionExtendedResult startTxnResult =
     (StartBatchedTransactionExtendedResult)
     connection.processExtendedOperation(startTxnRequest);
if (startTxnResult.getResultCode() != ResultCode.SUCCESS)
{
  throw new LDAPException(startTxnResult);
}
ASN1OctetString txnID = startTxnResult.getTransactionID();

// At this point, we have a transaction available for use.  If any error
// occurs, we will want to make sure that the transaction is aborted, so
// use a try/finally block to handle that.
boolean shouldAbort = true;
try
{
  // Create and send the first modify request as part of the transaction.
  // Make sure to include the batched transaction specification control and
  // the post-read request control in the modify request.
  ModifyRequest modifyRequest1 = new ModifyRequest(
       "cn=first,dc=example,dc=com",
       new Modification(ModificationType.REPLACE, "description", "first"));
  modifyRequest1.addControl(
       new BatchedTransactionSpecificationRequestControl(txnID));
  modifyRequest1.addControl(new PostReadRequestControl());
  LDAPResult modifyResult1 = connection.modify(modifyRequest1);

  // Create and send the second modify request as part of the transaction.
  // Again, make sure to include the appropriate controls in the request.
  ModifyRequest modifyRequest2 = new ModifyRequest(
       "cn=second,dc=example,dc=com",
       new Modification(ModificationType.REPLACE, "description", "second"));
  modifyRequest2.addControl(
       new BatchedTransactionSpecificationRequestControl(txnID));
  modifyRequest2.addControl(new PostReadRequestControl());
  LDAPResult modifyResult2 = connection.modify(modifyRequest1);

  // Now we're ready to commit, which we can do with the end batched
  // transaction request with the commit flag set to true.
  EndBatchedTransactionExtendedRequest commitRequest =
       new EndBatchedTransactionExtendedRequest(txnID, true);
  EndBatchedTransactionExtendedResult commitResult =
       (EndBatchedTransactionExtendedResult)
       connection.processExtendedOperation(commitRequest);
  if (commitResult.getResultCode() == ResultCode.SUCCESS)
  {
    System.out.println("The transaction was committed successfully.");

    // Everything was successful, so we don't need to abort anything.
    shouldAbort = false;

    // Get the post-read response control for the first modify operation.
    // It's the same process for the second, but this example is already
    // long enough so we'll skip it.
    Control[] controls = commitResult.getOperationResponseControls(
         modifyResult1.getMessageID());
    if (controls != null)
    {
      for (Control c : controls)
      {
        if (c instanceof PostReadResponseControl)
        {
          PostReadResponseControl postReadResponse =
               (PostReadResponseControl) c;
          System.out.println("First entry after the modification:");
          System.out.println(postReadResponse.getEntry().toLDIFString());
        }
      }
    }
  }
  else
  {
    // The transaction failed for some reason.  The response should tell us
    // whether it failed because of one of the operations.
    int failedOpMessageID = commitResult.getFailedOpMessageID();
    if (failedOpMessageID == modifyResult1.getMessageID())
    {
      System.err.println("The transaction failed because of a failure " +
           "encountered while processing the first modification.");
    }
    else if (failedOpMessageID == modifyResult2.getMessageID())
    {
      System.err.println("The transaction failed because of a failure " +
           "encountered while processing the second modification.");
    }
    else
    {
      System.err.println("The transaction failed for some reason other " +
           "than either of the modify operations.");
    }

    throw new LDAPException(commitResult);
  }
}
finally
{
  if (shouldAbort)
  {
    // Setting the commit flag to false in the end batched transaction
    // request will cause the transaction to be aborted rather than
    // committed.
    EndBatchedTransactionExtendedRequest abortRequest =
          new EndBatchedTransactionExtendedRequest(txnID, false);
    connection.processExtendedOperation(abortRequest);
  }
}
</pre>

              <p></p>
              <h3>Start and End Interactive Transaction</h3>

              <p>
                The start interactive transaction and end interactive transaction extended
                operations, and the associated interactive transaction specification request
                control, can be used to create an interactive transaction in which multiple
                operations are performed as a single atomic unit.  First, a start interactive
                transaction request is sent to the server, which will return a start interactive
                transaction result containing a transaction ID.  Each operation that should be
                performed as part of that transaction should then include the interactive
                transaction specification control containing that transaction ID.  Finally, the end
                interactive transaction request may be sent to the server to either commit or abort
                the transaction.
              </p>

              <p>
                Interactive transactions differ from batched transactions in a couple of key ways.
                First, interactive transactions may include read operations (e.g., search and
                compare) as well as write operations (e.g., add, delete, modify, and modify DN),
                whereas batched transactions only allow for write operations.  Second, the
                operations which are part of an interactive transaction are processed immediately
                by the server rather than being batched and processed later, which means that there
                is no need for special handling with regard to response controls.
              </p>

              <p>
                The following example illustrates the use of the start and end interactive
                transaction operations and the interactive transaction specification request
                control to perform a search and then modify all entries that match the associated
                search criteria:
              </p>

              <pre>
// Start the interactive transaction and get the transaction ID.
StartInteractiveTransactionExtendedRequest startTxnRequest =
     new StartInteractiveTransactionExtendedRequest("dc=example,dc=com");
StartInteractiveTransactionExtendedResult startTxnResult =
     (StartInteractiveTransactionExtendedResult)
     connection.processExtendedOperation(startTxnRequest);
if (startTxnResult.getResultCode() != ResultCode.SUCCESS)
{
  throw new LDAPException(startTxnResult);
}
ASN1OctetString txnID = startTxnResult.getTransactionID();

// At this point, we have a valid transaction.  We want to ensure that the
// transaction is aborted if any failure occurs, so do that in a
// try-finally block.
boolean txnFailed = true;
try
{
  // Perform a search to find all users in the "Sales" department.
  SearchRequest searchRequest =
       new SearchRequest("dc=example,dc=com", SearchScope.SUB, "(ou=Sales)");
  searchRequest.addControl(
       new InteractiveTransactionSpecificationRequestControl(txnID, true,
                                                           true));
  SearchResult searchResult = connection.search(searchRequest);
  if (searchResult.getResultCode() != ResultCode.SUCCESS)
  {
    throw new LDAPException(searchResult);
  }

  // Iterate through all of the users and assign a new fax number to each
  // of them.
  for (SearchResultEntry e : searchResult.getSearchEntries())
  {
    ModifyRequest modifyRequest = new ModifyRequest(e.getDN(),
         new Modification(ModificationType.REPLACE, "facsimileTelephoneNumber",
                          "+1 123 456 7890"));
    modifyRequest.addControl(
         new InteractiveTransactionSpecificationRequestControl(txnID, true,
                                                               true));
    connection.modify(modifyRequest);
  }

  // Commit the transaction.
  ExtendedResult endTxnResult = connection.processExtendedOperation(
       new EndInteractiveTransactionExtendedRequest(txnID, true));
  if (endTxnResult.getResultCode() == ResultCode.SUCCESS)
  {
    txnFailed = false;
  }
}
finally
{
  if (txnFailed)
  {
    connection.processExtendedOperation(
         new EndInteractiveTransactionExtendedRequest(txnID, false));
  }
}
</pre>

              <p></p>
              <h3>Stream Directory Values</h3>

              <p>
                The stream directory values operation may be used to request that a Directory
                Server retrieve information about all unique entry DNs and/or all unique
                values for a specified attribute or set of indexed attributes.  Although it is
                primarily used by the Directory Proxy Server for populating the entry-balancing
                global index, it may also be useful for other purposes (e.g., it provides a very
                efficient way to retrieve a list of the DNs of all entries in a specified portion
                of the DIT).
              </p>
